use std::{path::Path, sync::Arc};

use crate::data::AppState;
use axum::{
    body::Body,
    extract::State,
    http::{
        header::{CONTENT_DISPOSITION, CONTENT_LENGTH, CONTENT_TYPE},
        HeaderMap, HeaderValue, StatusCode,
    },
    response::{Html, IntoResponse, Response},
};

use futures::{stream::once, StreamExt};
use tokio_util::io::ReaderStream;
mod upload;
pub(crate) use upload::upload;

pub(crate) async fn get_file(State(data): State<AppState>) -> Response {
    let my_data = data;
    let path = my_data.filename.to_string();
    let is_upload = my_data.upload;
    let html = include_str!("../assets/index.html");
    if is_upload {
        Html(html).into_response()
    } else {
        let filename = Path::new(&path)
            .file_name()
            .and_then(|name| name.to_str())
            .unwrap_or("unknown");
        let file = match tokio::fs::File::open(&path).await {
            Ok(file) => file,
            Err(err) => {
                return (StatusCode::NOT_FOUND, format!("File not found,{}", err)).into_response()
            }
        };
        let total = file.metadata().await.unwrap().len();
        let progress = ml_progress::progress!(total).unwrap();
        let progress = Arc::new(progress);
        let stream = ReaderStream::new(file)
            .inspect({
                let progress = Arc::clone(&progress);
                move |chunk| {
                    let chunk = chunk.as_ref().unwrap();
                    let size = chunk.len();
                    progress.inc(size as u64);
                }
            })
            .chain(once(async move {
                progress.finish();
                Ok(axum::body::Bytes::new())
            }));
        let body = Body::from_stream(stream);
        let mut header = HeaderMap::new();
        header.insert(
            CONTENT_TYPE,
            HeaderValue::from_str("application/octet-stream").unwrap(),
        );
        header.insert(
            CONTENT_DISPOSITION,
            HeaderValue::from_str(&format!("attachment;filename={}", filename)).unwrap(),
        );
        header.insert(CONTENT_LENGTH, HeaderValue::from(total));
        (header, body).into_response()
    }
}
